#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <cassert>
#include <fstream>
#include "../comm/util.hpp"
#include "../comm/log.hpp"
#include "include/mysql.h"
using namespace std;

namespace ns_model
{
    using namespace ns_util;
    using namespace ns_log;

    // 包括一个题目的基本属性
    struct Question
    {
        std::string number; // 题目编号
        std::string title;  // 题目标题
        std::string star;   // 题目难度
        std::string desc;   // 题目描述
        std::string header; // 题目预设代码
        std::string tail;   // 题目的测试用例
        int cpu_limit;      // 时间限制
        int mem_limit;      // 空间限制
    };

    const static std::string table_name = "oj_questions";
    const static std::string host = "124.223.49.199";
    const static std::string user = "oj_client";
    const static std::string passwd = "zp010521";
    const static std::string db = "oj";
    const static uint64_t port = 3306;

    // 管理所有题目数据，为上层提供访问题目的接口
    class Model
    {
    public:
        /**
         * 获取所有题目列表
         * 参数：输出型参数，所有题目
         * */

        bool QueryMySQL(const std::string &sql, std::vector<Question> &out)
        {
            // 创建MySQL句柄
            MYSQL *my = mysql_init(nullptr);

            // 连接
            if (nullptr == mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0))
            {
                LOG(FATAL) << "连接数据库失败" << std::endl;
                return false;
            }

            LOG(INFO) << "连接数据库成功" << std::endl;

            // 连接成功后，必须设置该连接的编码格式（默认是拉丁的）
            mysql_set_character_set(my, "utf8");

            // 执行一条MySQL查询
            if (mysql_query(my, sql.c_str()) != 0)
            {
                LOG(WARNING) << "sql查询失败" << std::endl;
                return false;
            }

            // 提取结果
            MYSQL_RES *res = mysql_store_result(my);

            // 分析结果
            int rows = mysql_num_rows(res);   // 获得行数
            int cols = mysql_num_fields(res); // 获得列数

            Question q;

            for (int i = 0; i < rows; ++i)
            {
                // 从res中拿取一行结果(char**) (一行中又有许多列)
                MYSQL_ROW row = mysql_fetch_row(res);

                q.number = row[0];
                q.title = row[1];
                q.star = row[2];
                q.desc = row[3];
                q.header = row[4];
                q.tail = row[5];
                q.cpu_limit = atoi(row[6]);
                q.mem_limit = atoi(row[7]);

                out.push_back({q});
            }

            /**
             * 释放res空间
             * mysql_store_result保存结果的原理：
             * malloc开辟一段内存，然后将结果写入内存并返回该内存指针
             * 因此在最后使用完结果后，一定要释放对应的空间，否则一定会有内存泄漏问题
             */

            free(res);

            mysql_close(my);

            return true;
        }

        bool GetAllQuestion(std::vector<Question> &out)
        {
            std::string sql = "select * from ";
            sql += table_name;

            //LOG(INFO) << "发出sql语句: " << sql << std::endl;
            return QueryMySQL(sql, out);
        }

        /**
         * 获取指定题目
         * 参数1：题目编号
         * 参数2：输出型参数
         */
        bool GetOneQuestion(const std::string &number, Question &out)
        {
            bool bo = false;
            std::string sql = "select * from ";
            sql += table_name;
            sql += " where number = ";
            sql += number;

            //LOG(INFO) << "发出sql语句: " << sql << std::endl;

            std::vector<Question> res;
            if (QueryMySQL(sql, res))
            {
                if (res.size() == 1)
                {
                    out = res[0];
                    bo = true;
                }
            }

            return bo;
        }
    };

    //    class Model
    //     {
    //     public:
    //         Model()
    //         {}
    //         bool QueryMySql(const std::string &sql, vector<Question> *out)
    //         {
    //             // 创建mysql句柄
    //             MYSQL *my = mysql_init(nullptr);

    //             // 连接数据库
    //             if(nullptr == mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(),db.c_str(),port, nullptr, 0)){
    //                 LOG(FATAL) << "连接数据库失败!" << "\n";
    //                 return false;
    //             }

    //             // 一定要设置该链接的编码格式, 要不然会出现乱码问题
    //             mysql_set_character_set(my, "utf8");

    //             LOG(INFO) << "连接数据库成功!" << "\n";

    //             // 执行sql语句
    //             if(0 != mysql_query(my, sql.c_str()))
    //             {
    //                 LOG(WARNING) << sql << " execute error!" << "\n";
    //                 return false;
    //             }

    //             // 提取结果
    //             MYSQL_RES *res = mysql_store_result(my);

    //             // 分析结果
    //             int rows = mysql_num_rows(res); //获得行数量
    //             int cols = mysql_num_fields(res); //获得列数量

    //             Question q;

    //             for(int i = 0; i < rows; i++)
    //             {
    //                 MYSQL_ROW row = mysql_fetch_row(res);
    //                 q.number = row[0];
    //                 q.title = row[1];
    //                 q.star = row[2];
    //                 q.desc = row[3];
    //                 q.header = row[4];
    //                 q.tail = row[5];
    //                 q.cpu_limit = atoi(row[6]);
    //                 q.mem_limit = atoi(row[7]);

    //                 out->push_back(q);
    //             }
    //             // 释放结果空间
    //             free(res);
    //             // 关闭mysql连接
    //             mysql_close(my);

    //             return true;
    //         }
    //         bool GetAllQuestions(vector<Question> *out)
    //         {
    //             std::string sql = "select * from ";
    //             sql += table_name;
    //             return QueryMySql(sql, out);
    //         }
    //         bool GetOneQuestion(const std::string &number, Question *q)
    //         {
    //             bool res = false;
    //             std::string sql = "select * from ";
    //             sql += table_name;
    //             sql += " where number=";
    //             sql += number;
    //             vector<Question> result;
    //             if(QueryMySql(sql, &result))
    //             {
    //                 if(result.size() == 1){
    //                     *q = result[0];
    //                     res = true;
    //                 }
    //             }
    //             return res;
    //         }
    //         ~Model()
    //         {}
    //     };
}